package indi.zhifa.recipe.bailan5.coupon.serive.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import indi.zhifa.recipe.bailan.framework.auth.entity.dto.TokenObject;
import indi.zhifa.recipe.bailan.framework.auth.util.ITokenUtil;
import indi.zhifa.recipe.bailan.framework.common.entity.exception.ServiceException;
import indi.zhifa.recipe.bailan.framework.common.util.ZfFileMemo;
import indi.zhifa.recipe.bailan.framework.queue.entity.EQueueValueType;
import indi.zhifa.recipe.bailan.framework.queue.util.ZfRedisMqUtil;
import indi.zhifa.recipe.bailan.framework.redis.annotations.RedissonLock;
import indi.zhifa.recipe.bailan.framework.redis.util.RedisScriptUtil;
import indi.zhifa.recipe.bailan.framework.redis.util.RedisUtil;
import indi.zhifa.recipe.bailan5.coupon.dao.service.ICouponDbService;
import indi.zhifa.recipe.bailan5.coupon.dao.service.ICouponObjectDbService;
import indi.zhifa.recipe.bailan5.coupon.entity.po.CouponEntity;
import indi.zhifa.recipe.bailan5.coupon.entity.po.CouponObjectEntity;
import indi.zhifa.recipe.bailan5.coupon.entity.po.msg.CouponStorageMsg;
import indi.zhifa.recipe.bailan5.coupon.serive.ICouponObjectService;
import indi.zhifa.recipe.bailan5.coupon.util.AppConst;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Arrays;

@Slf4j
@RequiredArgsConstructor
@Service
public class CouponObjectServiceImpl implements ICouponObjectService {

    private final ICouponDbService mCouponDbService;
    private final ICouponObjectDbService mCouponObjectDbService;
    private final ITokenUtil mITokenUtil;

    private final ZfRedisMqUtil mZfRedisMqUtil;

    private final RedisScriptUtil mRedisScriptUtil;

    private final ZfFileMemo mZfFileMemo;

    @PostConstruct
    public void init() throws IOException {
        mZfFileMemo.loadFile(AppConst.DEDUCT_BUT_NOT_ZERO_FILE_KEY,AppConst.DEDUCT_BUT_NOT_ZERO_FILE_PATH);
    }

    @RedissonLock(keys = {"#pCouponId"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public CouponObjectEntity seizeCoupon(Long pUserId, Long pCouponId) throws InterruptedException {
        CouponEntity couponEntity = mCouponDbService.check(pCouponId);
        LocalDate expire = couponEntity.getExpireDate();
        if(LocalDate.now().isAfter(expire)){
            throw new ServiceException("该消费券已过期");
        }
        TokenObject tokenObject = mITokenUtil.getTokenObject();
        // check storage
        int storage = couponEntity.getStorage();
        log.info("用户"+tokenObject.getNickName()+"抢优惠券"+couponEntity.getName()+"_"+couponEntity.getId()+" 此时库存为"+storage);
        if(storage <= 0){
            throw new ServiceException("无库存");
        }
        // check available
        LambdaQueryWrapper<CouponObjectEntity> couponObjectQueryWrapper = Wrappers.<CouponObjectEntity>lambdaQuery()
                        .eq(CouponObjectEntity::getCouponId,pCouponId)
                        .eq(CouponObjectEntity::getUserId,tokenObject.getId());
        long cnt = mCouponObjectDbService.count(couponObjectQueryWrapper);
        int userGetMax = couponEntity.getUserGetMax();
        log.info("用户已拥有"+cnt+"个该优惠券");
        if(userGetMax >0 && cnt >= couponEntity.getUserGetMax()){
            throw new ServiceException("领取上限");
        }

        // 插入消费券实体
        CouponObjectEntity couponObjectEntity = new CouponObjectEntity();
        couponObjectEntity.createInit();
        couponObjectEntity.setCouponId(pCouponId);

        couponObjectEntity.setUserId(tokenObject.getId());
        couponObjectEntity.setUsed(false);
        couponObjectEntity.setCompanyAuthId(couponEntity.getCompanyAuthId());
        couponObjectEntity.setCouponId(pCouponId);
        couponObjectEntity.setExpireDate(couponEntity.getExpireDate());

        // 更新库存
        couponEntity.setStorage(storage-1);
        Thread.sleep(1000);
        mCouponDbService.updatePull(couponEntity.getId(),couponEntity);
        // 插入消费券实体
        Thread.sleep(3000);
        mCouponObjectDbService.save(couponObjectEntity);

        return couponObjectEntity;
    }

    @RedissonLock(keys = {"#pCouponId"+'-'+"#pUserId"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public CouponObjectEntity seizeCouponNew(Long pUserId, Long pCouponId) throws InterruptedException {
        CouponEntity couponEntity = mCouponDbService.check(pCouponId);
        Long storage = mRedisScriptUtil.execute(AppConst.DEDUCT_BUT_NOT_ZERO_FILE_KEY,Long.class, Arrays.asList(AppConst.COUPON_STORAGE_KEY,pCouponId.toString()));
        if(null != storage && storage > 0){
            CouponStorageMsg couponStorageMsg = new CouponStorageMsg();
            couponStorageMsg.setId(pCouponId);
            couponStorageMsg.setStorage(storage.intValue());
            mZfRedisMqUtil.sendMessage(AppConst.COUPON_STREAM,AppConst.COUPON_USE, EQueueValueType.JSON,couponStorageMsg);
            TokenObject tokenObject = mITokenUtil.getTokenObject();

            // check available
            LambdaQueryWrapper<CouponObjectEntity> couponObjectQueryWrapper = Wrappers.<CouponObjectEntity>lambdaQuery()
                    .eq(CouponObjectEntity::getCouponId,pCouponId)
                    .eq(CouponObjectEntity::getUserId,tokenObject.getId());
            long cnt = mCouponObjectDbService.count(couponObjectQueryWrapper);
            int userGetMax = couponEntity.getUserGetMax();
            log.info("用户已拥有"+cnt+"个该优惠券");
            if(userGetMax >0 && cnt >= couponEntity.getUserGetMax()){
                throw new ServiceException("领取上限");
            }

            CouponObjectEntity couponObjectEntity = new CouponObjectEntity();
            couponObjectEntity.createInit();
            couponObjectEntity.setCouponId(pCouponId);

            couponObjectEntity.setUserId(tokenObject.getId());
            couponObjectEntity.setUsed(false);
            couponObjectEntity.setCompanyAuthId(couponEntity.getCompanyAuthId());
            couponObjectEntity.setCouponId(pCouponId);
            couponObjectEntity.setExpireDate(couponEntity.getExpireDate());
            // 插入消费券实体
            Thread.sleep(3000);
            mCouponObjectDbService.save(couponObjectEntity);
            return couponObjectEntity;
        }else{
            throw new ServiceException("库存为空");
        }
    }

    @Override
    public Page<CouponObjectEntity> page(Integer pCurrent, Integer pSize, Long pUserId) {
        Page<CouponObjectEntity> couponObjectEntityCfg = new Page<>(pCurrent,pSize);
        LocalDate today = LocalDate.now();
        LambdaQueryWrapper<CouponObjectEntity> queryWrapper = Wrappers.<CouponObjectEntity>lambdaQuery()
                .eq(CouponObjectEntity::getUserId,pUserId)
                .ge(CouponObjectEntity::getExpireDate,today);
        return mCouponObjectDbService.page(couponObjectEntityCfg,queryWrapper);
    }

}
